﻿using System;
using System.Threading.Tasks;
using RotovapPlatform.Domain.Equipment.Interfaces.Base;

namespace RotovapPlatform.Domain.Equipment.Device.IO
{
	/// <summary>
	/// IO信号实体基类
	/// </summary>
	public abstract class IOSignal : IIOSignal
	{
		/// <summary>
		/// 信号ID
		/// </summary>
		public string Id { get; }

		/// <summary>
		/// 信号名称
		/// </summary>
		public string Name { get; }

		/// <summary>
		/// 信号描述
		/// </summary>
		public string Description { get; }

		/// <summary>
		/// 信号状态变化事件
		/// </summary>
		public event EventHandler<IOSignalStateChangedEventArgs> StateChanged;

		/// <summary>
		/// 构造函数
		/// </summary>
		protected IOSignal(string id, string name, string description)
		{
			Id = id ?? throw new ArgumentNullException(nameof(id));
			Name = name ?? throw new ArgumentNullException(nameof(name));
			Description = description ?? string.Empty;
		}

		/// <summary>
		/// 触发状态变化事件
		/// </summary>
		protected virtual void OnStateChanged(object oldState, object newState)
		{
			StateChanged?.Invoke(this, new IOSignalStateChangedEventArgs(Id, oldState, newState));
		}
	}

	/// <summary>
	/// 数字输入信号实体
	/// </summary>
	public class DISignal : IOSignal, IDISignal
	{
		private bool _state;

		/// <summary>
		/// 当前状态值
		/// </summary>
		public bool State
		{
			get => _state;
			internal set
			{
				if (_state == value) return;

				bool oldState = _state;
				_state = value;
				OnStateChanged(oldState, value);
			}
		}

		/// <summary>
		/// 信号通道编号
		/// </summary>
		public int Channel { get; }

		/// <summary>
		/// 构造函数
		/// </summary>
		public DISignal(string id, string name, string description, int channel)
			: base(id, name, description)
		{
			Channel = channel;
			_state = false;
		}

		/// <summary>
		/// 创建DI信号
		/// </summary>
		public static DISignal Create(DISignalId id, string description = null)
		{
			string name = id.ToString();
			string signalId = IOSignalUtils.GetDISignalName(id);
			return new DISignal(signalId, name, description ?? name, (int)id);
		}
	}

	/// <summary>
	/// 数字输出信号实体
	/// </summary>
	public class DOSignal : IOSignal, IDOSignal
	{
		private bool _state;

		/// <summary>
		/// 当前状态值
		/// </summary>
		public bool State
		{
			get => _state;
			internal set
			{
				if (_state == value) return;

				bool oldState = _state;
				_state = value;
				OnStateChanged(oldState, value);
			}
		}

		/// <summary>
		/// 信号通道编号
		/// </summary>
		public int Channel { get; }

		/// <summary>
		/// IO硬件访问接口
		/// </summary>
		private readonly Func<int, bool, Task<bool>> _writeOutputFunc;

		/// <summary>
		/// 构造函数
		/// </summary>
		public DOSignal(string id, string name, string description, int channel, Func<int, bool, Task<bool>> writeOutputFunc)
			: base(id, name, description)
		{
			Channel = channel;
			_state = false;
			_writeOutputFunc = writeOutputFunc ?? throw new ArgumentNullException(nameof(writeOutputFunc));
		}

		/// <summary>
		/// 设置信号状态
		/// </summary>
		public async Task<bool> SetStateAsync(bool state)
		{
			try
			{
				bool result = await _writeOutputFunc(Channel, state);
				if (result)
				{
					State = state; // 内部设置状态会触发事件
				}
				return result;
			}
			catch (Exception)
			{
				return false;
			}
		}

		/// <summary>
		/// 创建DO信号
		/// </summary>
		public static DOSignal Create(DOSignalId id, string description, Func<int, bool, Task<bool>> writeOutputFunc)
		{
			string name = id.ToString();
			string signalId = IOSignalUtils.GetDOSignalName(id);
			int physicalChannel = (int)id + 1;
			return new DOSignal(signalId, name, description ?? name, physicalChannel, writeOutputFunc);
		}
	}

	/// <summary>
	/// 模拟输入信号实体
	/// </summary>
	public class AISignal : IOSignal, IAISignal
	{
		private double _value;

		/// <summary>
		/// 当前模拟值
		/// </summary>
		public double Value
		{
			get => _value;
			internal set
			{
				if (Math.Abs(_value - value) < 0.001) return;

				double oldValue = _value;
				_value = value;
				OnStateChanged(oldValue, value);
			}
		}

		/// <summary>
		/// 信号通道编号
		/// </summary>
		public int Channel { get; }

		/// <summary>
		/// 信号量程下限
		/// </summary>
		public double MinValue { get; }

		/// <summary>
		/// 信号量程上限
		/// </summary>
		public double MaxValue { get; }

		/// <summary>
		/// 信号单位
		/// </summary>
		public string Unit { get; }

		/// <summary>
		/// 构造函数
		/// </summary>
		public AISignal(string id, string name, string description, int channel,
			double minValue, double maxValue, string unit)
			: base(id, name, description)
		{
			Channel = channel;
			MinValue = minValue;
			MaxValue = maxValue;
			Unit = unit ?? string.Empty;
			_value = 0;
		}

		/// <summary>
		/// 创建AI信号
		/// </summary>
		public static AISignal Create(AISignalId id, string description,
			double minValue, double maxValue, string unit)
		{
			string name = id.ToString();
			string signalId = IOSignalUtils.GetAISignalName(id);
			return new AISignal(signalId, name, description ?? name, (int)id, minValue, maxValue, unit);
		}
	}
}